package net.pulseproject.router.debuggerapp.view;

import java.awt.Color;
import java.awt.event.ActionEvent;

import javax.sound.midi.MidiUnavailableException;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import net.pulseproject.commons.gui.ActionListenerX;
import net.pulseproject.commons.gui.IconsCache;
import net.pulseproject.commons.midi.DebuggerLogic;
import net.pulseproject.commons.midi.entity.ControllerMessage;
import net.pulseproject.commons.midi.entity.Device;
import net.pulseproject.commons.midi.entity.MessageTemplate;
import net.pulseproject.commons.midi.entity.NoteMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SendPanel extends JPanel {

	private static final Log LOG = LogFactory.getLog(DevicePanel.class);
	
	private static final long serialVersionUID = -8045899533022202527L;
	
	private static final String TYPE_NOTE = "Note Message";

	private static final String TYPE_CONTROL = "Control Message";
	
	private final JComboBox messageType = new JComboBox(new String[] { TYPE_NOTE, TYPE_CONTROL });
	
	private final DebuggerLogic logic;
	
	private final Device device;
	
	private final DataForm formChannel = new DataForm(1);
	
	private final DataForm formData1 = new DataForm(0);
	
	private final DataForm formData2 = new DataForm(0);

	private final IconsCache iconsCache;
	
	
	public SendPanel(final IconsCache iconsCache, final JFrame parent, final DebuggerLogic logic, final Device device) {
		this.iconsCache = iconsCache;
		if(parent == null) { throw new IllegalArgumentException("parent == null"); }
		if(logic == null) { throw new IllegalArgumentException("logic == null"); }
		if(device == null) { throw new IllegalArgumentException("device == null"); }
		if(device.getState().isReceiving() == false) {
			throw new RuntimeException("Received non receivable device [" + device + "]!");
		}
		this.logic = logic;
		this.device = device;
		
		this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		
		final JButton btnSend = new JButton("Send");
		btnSend.addActionListener(new ActionListenerX(this.iconsCache, parent, "Could not send MIDI message!") {
			@Override protected void action(final ActionEvent e) {
				SendPanel.this.doSendDebugData();
		}});
		
		this.messageType.addActionListener(new ActionListenerX(this.iconsCache, parent, "Could not update message type!") {
			@Override protected void action(final ActionEvent event) {
				SendPanel.this.updateMessageType();
			}
		});
		this.add(this.messageType);
		this.formChannel.setLabel("MIDI Channel:");
		this.formChannel.setFieldTooltip("From 1 to 16");
		this.add(this.formChannel);
		this.add(this.formData1);
		this.add(this.formData2);
		this.add(btnSend);
		this.updateMessageType();
	}
	
	private void updateMessageType() {
		final boolean isNote = TYPE_NOTE.equals(this.messageType.getSelectedItem());
		this.formData1.setLabel(isNote ? "Note Number:" : "Control Number:");
		this.formData2.setLabel(isNote ? "Note Velocity:" : "Control Value:");
	}
	
	private void doSendDebugData() {
		
		final int channel = this.formChannel.getValue() - 1; // 1 to 0 based indexed
		final int data1 = this.formData1.getValue();
		final int data2 = this.formData2.getValue();
		final MessageTemplate template;
		
		if(TYPE_NOTE.equals(this.messageType.getSelectedItem()) == true) {
			template = new NoteMessage(channel, data1, data2);
		} else {
			template = new ControllerMessage(channel, data1, data2);
		}
		
		try {
			this.logic.sendMidi(this.device.getPortName(), template);
		} catch (final MidiUnavailableException e) {
			LOG.error("Could not send MIDI message!", e);
			JOptionPane.showMessageDialog(this, "Could not send data to MIDI port '" +
					this.device.getPortName() + "':\n" + e.getMessage(),
					"MIDI Error", JOptionPane.ERROR_MESSAGE);
		}
	}

	private static class DataForm extends JPanel {
		private static final long serialVersionUID = -4440720966303519767L;
		private final JLabel label = new JLabel();
		private final JTextField text = new JTextField();
		public DataForm(final int defaultValue) {
			this.add(this.label);
			this.add(this.text);
			this.text.setText(String.valueOf(defaultValue));
			this.text.setColumns(3);
		}
		public void setFieldTooltip(final String tooltip) {
			this.text.setToolTipText(tooltip);
		}
		public void setLabel(final String label) {
			this.label.setText(label);
		}
		public int getValue() {
			final String txt = this.text.getText();
			return Integer.parseInt(txt);
		}
	}
}
